#include "Date.h"
Date getCurDate()
{
	time_t t = time(NULL);
	struct tm* lt = localtime(&t);
	return Date(lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday);
}

bool validatelunar(int lyear, int lmonth, int lday)
{
    return lyear > 0 && lmonth >= 1 && lmonth <= 13 && lday >= 1 && lday <= 30;
}

bool validatesolar(int year, int month, int day)
{
    if (year <= 0 || month <= 0 || day <= 0 || month > 12)
        return false;
    if (month == 2)
    {
        if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
        {
            if (day > 29)
                return false;
        }
        else
        {
            if (day > 28)
                return false;
        }
    }
    if (month == 4 || month == 6 || month == 9 || month == 11)
        if (day > 30)
            return false;
    if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)
        if (day > 31)
            return false;
    return true;
}

inline int GetBitInt(int data, int len, int shift)//注：1月在高位，13在低位，故使用时需要倒序索引
{
	int mask = ((1 << len) - 1) << shift;//生成len位全为1的掩码，左移shift位
	return (data & mask) >> shift;//按位与后右移shift位，得到len位数值，右移shift位后得到原数据对应位数值
}

long long Solar2Int(int y, int m, int d)
{
	long long total = 365 * y + y / 4 - y / 100 + y / 400;
	int months[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0)
		months[2] = 29;
	for (int i = 1; i < m; i++)
		total += months[i];
	total += d;
	return total;
}

Date Int2Solar(long long day)
{
	Date solar;
	long long y = 0;
	long long total = 0;
	while (total <= day)
	{
		int d;
		if(y % 4 == 0 && y % 100 != 0 || y % 400 == 0)
			d = 366;
		else
			d = 365;
		if (total + d > day)
			break;
		total += d;
		y++;
	}
	long long tem = day - total;
	int months[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0)
		months[2] = 29;
	int m = 1;
	while (tem > months[m])
	{
		tem-=months[m];
		m++;
	}
	solar.year = y;
	solar.month = m;
	solar.day = tem;
	return solar;
}

Date Lunar2Solar(Lunar lunar)
{
	int days = lunar_month_days[lunar.lyear - lunar_month_days[0]];//获取当年编码数据
	int leap = GetBitInt(days, 4, 13);
	int offset = 0;
	int loopend = leap;
	if(lunar.lmonth ==leap)
		lunar.isleap = true;
	else
		lunar.isleap = false;
	//处理闰月
	if (!lunar.isleap)
	{
		if (lunar.lmonth <= leap || leap == 0)//无闰月或闰月在目标之后，累加前n-1个月
		{
			loopend = lunar.lmonth - 1;
		}
		else//闰月在目标月之前，累加前n个月
		{
			loopend = lunar.lmonth;
		}
	}
	for (int i = 0; i < loopend; i++)
	{
		offset += GetBitInt(days, 1, 12 - i) == 1 ? 30 : 29;
	}
	offset += lunar.lday;
	int solar11=solar_1_1[lunar.lyear-solar_1_1[0]];//当年阳历1月1日日期
	int y = GetBitInt(solar11, 12, 9);
	int m = GetBitInt(solar11, 4, 5);
	int d = GetBitInt(solar11, 5, 0);
	return Int2Solar(Solar2Int(y, m, d) + offset);
}

Lunar Solar2Lunar(Date solar)
{
	Lunar lunar;
	int index = solar.year - solar_1_1[0];
	int data = (solar.year << 9) | (solar.month << 5) | (solar.day);//阳历日期编码
	int solar11 = 0;
	if (solar_1_1[index] > data)//若日期在正月初一之前，则属于上一年
		index--;
	solar11 = solar_1_1[index];//当年阳历1月1日日期
	int y = GetBitInt(solar11, 12, 9);
	int m = GetBitInt(solar11, 4, 5);
	int d = GetBitInt(solar11, 5, 0);
	long diff = Solar2Int(solar.year, solar.month, solar.day) - Solar2Int(y, m, d);
	int days = lunar_month_days[index];
	int leap = GetBitInt(days, 4, 13);
	int lyear=index+solar_1_1[0];
	int lmonth = 1;
	int lday;
	diff += 1;//正月初一为农历第一天，diff从1开始
	for (int i = 0; i < 13; i++)
	{
		int dayinmonth = GetBitInt(days, 1, 12 - i) == 1 ? 30 : 29;
		if (diff > dayinmonth)
		{
			diff -= dayinmonth;
			lmonth++;
		}
		else 
		{
			break;
		}
	}
	lday = (int)diff;
	lunar.lyear = lyear;
	lunar.lmonth = lmonth;
	//处理闰月
	lunar.isleap = false;
	if (leap != 0 && lmonth > leap)//有闰月，且当前月份在闰月之后
	{
		lunar.lmonth = lmonth - 1;
		if (lmonth == leap + 1)
		{
			lunar.isleap = true;
		}
	}
	lunar.lday = lday;
	return lunar;
}

int months[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
const Date base = { 1897,1,1 };
int basetian = 6, basedi = 8;

bool isleap(int year)
{
    if (year % 4 == 0 && year % 100 != 0) return true;
    if (year % 400 == 0) return true;
    return false;
}
void setColor(Color fg, Color bg) {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hConsole, (WORD)(fg | bg)); // 背景固定为白色
}

// 初始化控制台：白底黑字
void initConsole() {
    setColor(BLACK, WHITE_BACKGROUND); // 默认前景黑色，背景白色
    system("cls"); // 清屏
}

vector<std::pair<std::string, Date>> calculateJieqi(int year) {
    double D = 0.2422;
   
    int tmp = year % 100;
    int c = year / 100;
    bool isLeap = isleap(year);
    const double* jieqiC = jieqiC0;
    if (c == 18)jieqiC = jieqiC0;
    else if (c == 19)jieqiC = jieqiC2;
    else if (c == 20)jieqiC = jieqiC1;

    std::vector<std::pair<std::string, Date>> jieqidate;
    for (int i = 0; i < 24; i++) {
        int month = 1 + i / 2;
        int day = (int)(tmp * D + jieqiC[i]) - (isLeap ? (int)((tmp - 1) / 4) : (int)(tmp / 4));
        if (year == 2026 && i == 3) day--;
        else if (year == 2084 && i == 5) day++;
        else if (year == 1911 && i == 8) day++;
        else if (year == 2008 && i == 9) day++;
        else if (year == 1902 && i == 10) day++;
        else if (year == 1928 && i == 11) day++;
        else if ((year == 1925 || year == 2016) && i == 12) day++;
        else if (year == 1922 && i == 13) day++;
        else if (year == 2002 && i == 14) day++;
        else if (year == 1927 && i == 16) day++;
        else if (year == 1942 && i == 17) day++;
        else if (year == 2089 && i == 19) day++;
        else if (year == 2089 && i == 20) day++;
        else if (year == 1978 && i == 21) day++;
        else if (year == 1954 && i == 22) day++;
        else if ((year == 1918 || year == 2021) && i == 23) day--;
        else if ((year == 1982 || year == 2000) && i == 0) day++;
        else if (year == 2019 && i == 0) day--;
        else if ((year == 2000 || year == 2082) && i == 1) day++;
        else if (year == 1840 && i == 2)day--;
        else if (year == 1893 && i == 11)day--;
        jieqidate.emplace_back(jq[i], Date{ year, month, day });
    }
    return jieqidate;
}

void showmonth(int year, int month)
{
    //获取节气
    auto jieqidate = calculateJieqi(year);
    int days = months[month];
    if (month == 2 && isleap(year)) days = 29;

    Date first = { year, month, 1 };
    int m=first.month;
    int y=first.year;
    int W;
    if (m == 1 || m == 2)
    {
        m += 12;
        y--;
        W = (first.day + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400 + 1) % 7;
    }
    else
    {
        W = (first.day + 2 * first.month + 3 * (first.month + 1) / 5 + first.year + first.year / 4 - first.year / 100 + first.year / 400 + 1) % 7;
    }cout << "\t\t\t" << year << "年" << month << "月" << endl;
    cout << "\t日\t\t一\t\t二\t\t三\t\t四\t\t五\t\t六" << endl;
    cout << "----------------------------------------------------------------------------------------------------------"<<endl;
    vector<vector<int>>calendar(6, vector<int>(7, 0));
    int currentday = 1, currentweek = 0, dayinweek = W  % 7;
    //currentday为当前日期，currentweek为当前周，dayinweek为当前日为当前周的第几天，即周几
    while (currentday <= days)
    {
        calendar[currentweek][dayinweek] = currentday;
        currentday++;
        dayinweek = (dayinweek + 1) % 7;
        if (dayinweek == 0)currentweek++;
    }
    for (auto weekdate : calendar)
    {
        cout << "\t";
        for (auto day : weekdate)
        {

            if (day == 0)
            {
                cout << "\t\t";
                continue;
            }
            Date currentdate = { year,month,day };
            int weeknum = (W + day - 1) % 7;
            Color fg = BLACK;
            if (weeknum == 0 || weeknum == 6)
                fg = RED;
            for (auto jqdate : jieqidate)
            {
                if (jqdate.second.year == currentdate.year && jqdate.second.month == currentdate.month && jqdate.second.day == currentdate.day)
                {
                    fg = BLUE;
                    break;
                }
            }
            setColor(fg, WHITE_BACKGROUND);
            cout << setw(2) << day << "\t\t";
        }
        cout << endl;
        setColor(BLACK, WHITE_BACKGROUND);
        for (auto day : weekdate)
        {
            if (day == 0)
            {
                cout << "\t\t";
                continue;
            }
            Lunar lunar = Solar2Lunar(Date(year, month, day));
            string lunarstr;
            if (lunar.isleap)
            {
                lunarstr = "闰" + lunarMonthNames[lunar.lmonth] + lunarDayNames[lunar.lday];
            }
            else
            {
                if (lunar.lmonth > 12)
                    lunar.lmonth %= 12;
                lunarstr = lunarMonthNames[lunar.lmonth] + lunarDayNames[lunar.lday];
            }
            Date currentdate = { year,month,day };
            int weeknum = (W + day - 1) % 7;
            Color fg = BLACK;
            if (weeknum == 0 || weeknum == 6)
                fg = RED;
            for (auto jqdate : jieqidate)
            {
                if (jqdate.second.year == currentdate.year && jqdate.second.month == currentdate.month && jqdate.second.day == currentdate.day)
                {
                    fg = BLUE;
                    lunarstr = jqdate.first;
                    break;
                }
            }
            setColor(fg, WHITE_BACKGROUND);
            cout << setw(10) << lunarstr << "\t";
        }
        cout << endl;
    }
}

void day2now(Date solar)
{
    Date now = getCurDate();
    int diff = Solar2Int(now.year, now.month, now.day) - Solar2Int(solar.year, solar.month, solar.day);
    cout << solar.year << " " << solar.month << " " << solar.day << "比今天"
        << "(" << now.year << "-" << now.month << "-" << now.day << ")";
    if (diff > 0)cout << "早";
    else cout << "晚";
    cout << abs(diff) << "天";
}

void now2day(int tday)
{
    Date now = getCurDate();
    cout << "距离今天" << "(" << now.year << "-" << now.month << "-" << now.day << ")"
        << "【" << tday << "】天的日期为\n";
    Date day1 = Int2Solar(Solar2Int(now.year, now.month, now.day) + tday + 1);
    Date day2 = Int2Solar(Solar2Int(now.year, now.month, now.day) - tday + 2);
    int W1 = (day1.day + 2 * day1.month + 3 * (day1.month + 1) / 5 + day1.year + day1.year / 4 - day1.year / 100 + day1.year / 400) % 7;
    int W2 = (day2.day + 2 * day2.month + 3 * (day2.month + 1) / 5 + day2.year + day2.year / 4 - day2.year / 100 + day2.year / 400) % 7;
    cout << day2.year << " " << day2.month << " " << day2.day << weekday[W2] << endl;
    cout << day1.year << " " << day1.month << " " << day1.day << weekday[W1] << endl;
}


void diffday(Date solar1, Date solar2)
{
    if ((solar1.month > 12 || solar1.month < 1 || solar2.month>12 || solar2.month < 1) ||
        (isleap(solar1.year) && solar1.month == 2 && solar1.day > 29) ||
        (isleap(solar2.year) && solar2.month == 2 && solar2.day > 29) ||
        (solar1.month != 2 && solar1.day > months[solar1.month]) ||
        (solar2.month != 2 && solar2.day > months[solar2.month]))
    {
        cout << "日期输入错误！";
        return;
    }
    int diff = Solar2Int(solar2.year, solar2.month, solar2.day) - Solar2Int(solar1.year, solar1.month, solar1.day);
    cout << "两天相差" << abs(diff) << "天";
}


void jieqi(int year) {
    auto jieqidate = calculateJieqi(year);
    for (const auto& jq : jieqidate)
    {
        std::cout << jq.first << ":" << jq.second.month << "月" << jq.second.day << std::endl;
    }
}

void tiangan(Date solar)
{
    int yeartian = (solar.year - 3) % 10;
    int yeardi = (solar.year - 3) % 12;
    string yeargz = tian[yeartian] + di[yeardi];
    int monthdi = (solar.month + 1) % 12;
    int monthgan = (yeartian * 2 + solar.month - 1) % 10;
    string monthgz = tian[monthgan] + di[monthdi];
    int tmp = Solar2Int(solar.year, solar.month, solar.day) - Solar2Int(base.year, base.month, base.day);
    tmp %= 60;
    int daygan = (tmp + basetian) % 10;
    int daydi = (tmp + basedi) % 12;
    string daygz = tian[daygan] + di[daydi];
    cout << "\t\t" << yeargz << "年" << monthgz << "月" << daygz << "日" << endl;
}

void showfestival(int op)
{
    if (op == 1)
    {
        cout << "请输入月份：";
        int month;
        cin >> month;
        for (auto& p : solarfestival)
        {
            if (p.first.first == month)
                cout << p.second << ":" << p.first.first << "月" << p.first.second << "日" << endl;
            if (p.first.first > month)
                break;
        }
        if (month == 5)
            cout << "母亲节:" << month << "月第二个星期日" << endl;
        if (month == 6)
            cout << "父亲节:" << month << "月第三个星期日" << endl;
        if (month == 11)
            cout << "感恩节:" << month << "月第四个星期四" << endl;
    }
    else if (op == 2)
    {
        for (auto& p : lunarfestival)
        {
            cout << p.second << ":农历" << p.first.first << "月" << p.first.second << "日" << endl;
        }
    }
}

void week(int year, int month, int day)//基姆拉尔森公式计算星期
{
    if (month < 3)
    {
        year--;
        month += 12;
    }
    int W = (day + 2 * month + 3 * (month + 1) / 5 + year + year / 4 - year / 100 + year / 400 + 1) % 7;
    cout << "\t\t" << weekday[W] << endl;
}

void isJieqi(Date solar)
{
    auto jieqidate = calculateJieqi(solar.year);
    bool flag = false;
    for (auto& jq : jieqidate)
    {
        if (solar.year == jq.second.year && solar.month == jq.second.month && solar.day == jq.second.day)
        {
            cout << jq.first << endl;
            flag = true;
            break;
        }
    }
    if (!flag)
    {
        for (auto& jq : jieqidate)
        {
            if (Solar2Int(solar.year, solar.month, solar.day) < Solar2Int(jq.second.year, jq.second.month, jq.second.day))
            {
                cout << "\t\t" << Solar2Int(jq.second.year, jq.second.month, jq.second.day) - Solar2Int(solar.year, solar.month, solar.day) << "天后是" << jq.first << endl;
                flag = true;
                break;
            }
        }
    }
}